#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include "cam_suite.h"

#define DEFAULT_INPUT_FILENAME "/tmp/in-bmp%06d.bmp"
#define DEFAULT_OUTPUT_FILENAME "/tmp/out-bmp%06d.bmp"
//#define FFMPEG_CAPTURE "ffmpeg -f video4linux2 -s %dx%d -r %d -i /dev/video%d"
//#define FFMPEG_OUTPUT " -f image2 " INPUT_FILENAME
#define max(a,b) ((a)>(b)?(a):(b))
#define GREEN_THRESHOLD 20
#define COUNT_THRESHOLD 3

static CaptureContext *defaultContext = NULL;

static void checkDefaultContext() {
    if (!defaultContext) {
        defaultContext = (CaptureContext *)malloc(sizeof(CaptureContext));
        defaultContext->inputFn = (char *)malloc(strlen(DEFAULT_INPUT_FILENAME) + 1);
        strcpy(defaultContext->inputFn, DEFAULT_INPUT_FILENAME);
        defaultContext->outputFn = (char *)malloc(strlen(DEFAULT_OUTPUT_FILENAME) + 1);
        strcpy(defaultContext->outputFn, DEFAULT_OUTPUT_FILENAME);
        defaultContext->pict = 0;
        defaultContext->pictMemSize = 0;
        defaultContext->width = 0;
        defaultContext->height = 0;
        defaultContext->lastInputNumber = 0;
    }
}

int camGetHeight(CaptureContext *ctx) { return ctx->height; }
int camGetWidth(CaptureContext *ctx) { return ctx->width; }
int camGetHeight() { checkDefaultContext(); return camGetHeight(defaultContext); }
int camGetWidth() { checkDefaultContext(); return camGetWidth(defaultContext); }

int analyzePicture(CaptureContext *ctx, int *avgRow, int *avgCol) {
    int i, j;
    int sr = 0, sc = 0;
    int count = 0;
    for (i = 0; i < ctx->height; i++)
        for (j = 0; j < ctx->width; j++) {
            int nv = (int)ctx->pict[i * ctx->width + j][1] - max(ctx->pict[i * ctx->width + j][0], ctx->pict[i * ctx->width + j][2]);
            if (nv > GREEN_THRESHOLD) {
                count++;
                sr += i;
                sc += j;
            }
        }
    if (count >= COUNT_THRESHOLD) {
        *avgRow = sr / count;
        *avgCol = sc / count;
#if DEBUG
        fprintf(stderr, "avg.point = (%03d, %03d) count=%03d\n", sr / count, sc / count, count);
#endif
    }
    return count;
}

int analyzePicture(int *avgRow, int *avgCol) {
    checkDefaultContext();
    return analyzePicture(defaultContext, avgRow, avgCol);
}

int savePicture(CaptureContext *ctx) {
    FILE *f;
    char buf[400];
    buf[sprintf(buf, ctx->outputFn, ctx->lastInputNumber)] = 0;
    f = fopen(buf, "wb");
    fwrite(ctx->bmphead, 54, 1, f);
    fwrite(ctx->pict, ctx->height, ctx->width * 3, f);
    fclose(f);
    return 0;
}

int savePicture() {
    checkDefaultContext();
    return savePicture(defaultContext);
}

int loadPictureBlocking(CaptureContext *ctx) {
    FILE *f = 0;
    char buf[400];

    int number = ctx->lastInputNumber + 1;
    ctx->lastInputNumber = number;

    buf[sprintf(buf, ctx->inputFn, number)] = 0;

#if DEBUG
    fprintf(stderr, "Waiting for %s... ", buf);
    fflush(stderr);
#endif
    while (!f) {
        usleep(10000);
        f = fopen(buf, "r");
    }
#if DEBUG
    fprintf(stderr, "catched!\n");
#endif

    fread(ctx->bmphead, 54, 1, f);
    ctx->width = *((int *)(ctx->bmphead + 18));
    ctx->height = *((int *)(ctx->bmphead + 22));
    if (ctx->pictMemSize < ctx->width * ctx->height * 3) {
        ctx->pictMemSize = ctx->width * ctx->height * 3;
        if (ctx->pict)
            ctx->pict = (uint8_t (*)[3])realloc(ctx->pict, ctx->pictMemSize);
        else
            ctx->pict = (uint8_t (*)[3])malloc(ctx->pictMemSize);
    }
    fread(ctx->pict, ctx->height, ctx->width * 3, f);

    fclose(f);
    unlink(buf);

    return 0;
}

int loadPictureBlocking() {
    checkDefaultContext();
    return loadPictureBlocking(defaultContext);
}
